from .dsdiffdef import * 
from .id3tag import new_ID3_tag

def CopyBytes(ffin, ffout, size):
	buf = ffin.read(size)
	ffout.write(buf)

def modify_chunk_size(ffout, oldHead, newSize):
	buf = struct.pack(">IQ", oldHead[0], newSize)
	ffout.write(buf)

def getSomeChunkInfo(ff, id):
    header = ""
    offset = -1
    while(True):
        header = GetChunkInfo(ff)
        id1 = header[0].to_bytes(4, byteorder="big", signed=False)
        if(id1 == id):
            offset = ff.tell()
            print("Find ", id, "chunk at offset: ", offset)
            break
        else:
            ff.seek(header[1], 1)
    return header, offset

def getPROPChunkInfo(ff, id):
    return getSomeChunkInfo(ff, b'PROP')

def GetChunkInfo(ff):
    try:
        chunk = ff.read(12)
        print(chunk)
        ivar = struct.unpack(">IQ",chunk)
    except EOFError:
        ivar = ""	
    return ivar

def getDSDFormChunkInfo(ff):
	
    ivar = GetChunkInfo(ff)
    if(ivar != ""):    
        id = ivar[0].to_bytes(4, byteorder="big", signed=False)
        if(id == b'FRM8'):
            return ivar
    print("Error, not a DSDIFF file!")
    return ivar

def reuse_ID3_chunk(fin, fout):

    ffin = open(fin, "rb")

    header = getDSDFormChunkInfo(ffin)
    ffin.seek(FormDSDChunkHeaderSize)
    propHead, propOffset = getSomeChunkInfo(ffin, b'PROP')
    ffin.seek(propHead[1],1)
    diinHead, diinOffset = getSomeChunkInfo(ffin, b'DIIN')
    ffin.seek(diinHead[1],1)
    id3cHead, id3cOffset = getSomeChunkInfo(ffin, b'ID3 ')

    if(header =="" or propHead=="" or diinHead =="" or id3cHead ==""):
        ffin.close()
        return False

    lenToDelete = diinHead[1] + 12
    lenToAdd = id3cHead[1] + 12
    lenTotal = header[1] + lenToAdd - lenToDelete
    lenProp = propHead[1] + lenToAdd
    
    print(fin," Change chunk size from ", header[1], " to ", lenTotal)

    ffout = open(fout, "wb")

    #Modify total size
    modify_chunk_size(ffout, header, lenTotal)
    ffin.seek(12)

    #Copy bytes till PROP chunk
    CopyBytes(ffin, ffout, propOffset-12-12)

    #Modify PROP chunk size
    modify_chunk_size(ffout, propHead, lenProp)
    ffin.seek(12,1)

    #Copy old PROP chunk bytes
    CopyBytes(ffin, ffout, propHead[1])

    #Copy old ID3 chunk bytes
    ffin.seek(id3cOffset-12)
    CopyBytes(ffin, ffout, lenToAdd)
    ffin.seek(propOffset+propHead[1])
    
    #Copy bytes between PROP chunk and DIIN chunk
    CopyBytes(ffin, ffout, diinOffset - propOffset - propHead[1] - 12)

    #Skip DIIN chunk
    ffin.seek(diinOffset+diinHead[1])

    #Copy left bytes
    CopyBytes(ffin, ffout, header[1]-ffin.tell()+12)

    ffin.close()
    ffout.close()
    return True

#def create_new_chunk(bstrtype, size):
#    return 

def replace_ID3_chunk(fin, fout, singleTag):

    id3Tag = new_ID3_tag(singleTag)

    ffin = open(fin, "rb")

    header = getDSDFormChunkInfo(ffin)
    ffin.seek(FormDSDChunkHeaderSize)

    propHead, propOffset = getSomeChunkInfo(ffin, b'PROP')
    if(header =="" or propHead==""):
        ffin.close()
        return False

    ffin.seek(propHead[1],1)
    diinHead, diinOffset = getSomeChunkInfo(ffin, b'DIIN')
    ffin.seek(diinHead[1],1)
    if(diinHead !=""):
        lenToDelete = diinHead[1] + 12
    else:
        lenToDelete = 0


    buf = struct.pack(">4sQ", b'ID3 ', len(id3Tag)) + id3Tag
    lenToAdd = len(buf)

    lenTotal = header[1] + lenToAdd - lenToDelete
    lenProp = propHead[1] + lenToAdd
    
    print(fin," Change chunk size from ", header[1], " to ", lenTotal)

    ffout = open(fout, "wb")

    #Modify total size
    modify_chunk_size(ffout, header, lenTotal)
    ffin.seek(12)

    #Copy bytes till PROP chunk
    CopyBytes(ffin, ffout, propOffset-12-12)

    #Modify PROP chunk size
    modify_chunk_size(ffout, propHead, lenProp)
    ffin.seek(12,1)

    #Copy old PROP chunk bytes
    CopyBytes(ffin, ffout, propHead[1])

    #Copy new ID3 chunk bytes
    #ffin.seek(id3cOffset-12)
    #CopyBytes(ffin, ffout, lenToAdd)
    ffout.write(buf)
    ffin.seek(propOffset+propHead[1])
    
    if(lenToDelete != 0):
        #Copy bytes between PROP chunk and DIIN chunk
        CopyBytes(ffin, ffout, diinOffset - propOffset - propHead[1] - 12)
        #Skip DIIN chunk
        ffin.seek(diinOffset+diinHead[1])

    #Copy left bytes
    CopyBytes(ffin, ffout, header[1]-ffin.tell()+12)

    ffin.close()
    ffout.close()
    return True